package com.manager.common.utils;

import com.manager.common.annotation.Alise;
import jakarta.persistence.Transient;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.type.*;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;


@SuppressWarnings("all")
public class ClassUtils {

    public static Object invokeGet(Object o, Field field) {

        try {

            field.setAccessible(true);
            return field.get(o);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Object invokeGet(Object o, String fieldName) {

        Field field = null;

        try {
            field = o.getClass().getField(fieldName);
        } catch (Exception e) {
            try {
                field = o.getClass().getDeclaredField(fieldName);
            } catch (Exception ex) {
            }
        }
        try {

            field.setAccessible(true);
            return field.get(o);
        } catch (Exception e) {
        }
        return null;
    }

    public static <T> T invokeGet(Object o, String fieldName, Class<T> claz) {
        Object result = invokeGet(o, fieldName);
        if (result != null) {
            return (T) result;
        }
        return null;
    }

    public static boolean invokeSet(Object o, String fieldName, Object[] params) {

        Field field = null;

        try {
            field = o.getClass().getField(fieldName);
        } catch (Exception e) {
            try {
                field = o.getClass().getDeclaredField(fieldName);
            } catch (Exception ex) {
            }
        }
        try {

            field.setAccessible(true);
            field.set(o, params[0]);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static Method getGetMethod(Class objectClass, String fieldName) {
        try {

            if (checkSecendChar(fieldName)) {
                return objectClass.getMethod("get" + fieldName, new Class<?>[]{});
            }
            PropertyDescriptor pd = new PropertyDescriptor(fieldName, objectClass);
            return pd.getReadMethod();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static boolean checkSecendChar(String fieldName) {
        if (StringUtils.isBlank(fieldName) || fieldName.length() < 2) {
            return false;
        }
        char c = fieldName.substring(1, 2).charAt(0);
        if (Character.isUpperCase(c)) {
            return true;
        }
        return false;
    }

    public static Method getSetMethod(Class objectClass, String fieldName) {
        try {
            if (checkSecendChar(fieldName)) {
                return objectClass.getMethod("set" + fieldName, new Class<?>[]{});
            }
            PropertyDescriptor pd = new PropertyDescriptor(fieldName, objectClass);
            return pd.getWriteMethod();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Map<String, BasicTypeReference> classToSsqlQuery(Class<?> claz) throws Exception {
        Map<String, BasicTypeReference> map = new HashMap<>();
        List<Field> list = new ArrayList<>();
        list.addAll(Arrays.asList(claz.getDeclaredFields()));
        String scala = "";
        for (Field f : list) {
            Alise alise = f.getAnnotation(Alise.class);
            if (alise == null) {
                continue;
            }
            BasicTypeReference type = checkFieldType(f.getType().getName());
            if (type != null && checkField(f.getName(), claz)) {
                scala += ".addScalar(\"" + f.getName() + "\",StringType.INSTANCE)";
                map.put(f.getName(), type);
            }
        }
        return map;
    }

    private static boolean checkField(String fieldName, Class<?> claz) throws NoSuchMethodException, SecurityException {
        boolean mark = false;
        try {
            Method m = claz.getMethod("get" + fieldName, new Class<?>[]{});
            if (m != null && m.getAnnotation(Transient.class) == null) {
                mark = true;
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
        try {
            Method m = claz.getMethod("get" + dealMethodName(fieldName), new Class<?>[]{});
            if (m != null && m.getAnnotation(Transient.class) == null) {
                mark = true;
            }
        } catch (Exception e) {
            // TODO: handle exception
        }

        return mark;
    }

    private static String dealMethodName(String fieldName) {
        char[] cs = fieldName.toCharArray();
        char c = (char) ((int) cs[0] - 32);
        cs[0] = c;
        return String.valueOf(cs);
    }

    public static void setFieldValue(Object obj, String value, String fieldName) throws Exception {
        Field field = null;
        Class<?> clazz = obj.getClass();
        while (clazz != null && field == null){
            try{
                field = clazz.getDeclaredField(fieldName);
            }catch (Exception e){
                clazz = clazz.getSuperclass();
            }
        }
        if(field == null){
            return;
        }
        setFieldValue(obj, value, field);
    }


    public static void setFieldValue(Object obj, String value, Field field) throws Exception {
        if (StringUtils.isEmpty(value.trim())) {
            return;
        }
        String claz = field.getType().getName();
        field.setAccessible(true);

        if (claz.equals(String.class.getName())) {

            field.set(obj, value);

        } else if (claz.equals(Integer.class.getName())) {

            field.set(obj, Integer.parseInt(value));

        } else if (claz.equals(int.class.getName())) {

            field.set(obj, (int) Integer.parseInt(value));

        } else if (claz.equals(Float.class.getName())) {

            field.set(obj, Float.valueOf(value));

        } else if (claz.equals(float.class.getName())) {

            field.set(obj, (float) Float.parseFloat(value));

        } else if (claz.equals(Double.class.getName())) {

            field.set(obj, Double.valueOf(value));

        } else if (claz.equals(double.class.getName())) {

            field.set(obj, (double) Double.parseDouble(value));

        } else if (claz.equals(long.class.getName())) {

            field.set(obj, (long) Long.parseLong(value));

        } else if (claz.equals(Long.class.getName())) {

            field.set(obj, Long.valueOf(value));

        } else if (claz.equals(char.class.getName())) {

            field.set(obj, value.toCharArray()[0]);

        } else if (claz.equals(char[].class.getName())) {

            field.set(obj, value.toCharArray());

        } else if (claz.equals(Short.class.getName())) {

            field.set(obj, Short.valueOf(value));

        } else if (claz.equals(short.class.getName())) {

            field.set(obj, (short) Short.parseShort(value));
        } else if (claz.equals(BigDecimal.class.getName())) {

            field.set(obj, new BigDecimal(value));
        }
    }

    private static void paramType(String claz, String cellStr, List<Object> params) {
        if (claz.equals(String.class.getName())) {
            params.add(cellStr);
        } else if (claz.equals(Integer.class.getName())) {
            params.add(Integer.valueOf(cellStr));
        } else if (claz.equals(int.class.getName())) {
            params.add((int) Integer.parseInt(cellStr));
        } else if (claz.equals(Float.class.getName())) {
            params.add(Float.valueOf(cellStr));
        } else if (claz.equals(float.class.getName())) {
            params.add((float) Float.parseFloat(cellStr));
        } else if (claz.equals(Double.class.getName())) {
            params.add(Double.valueOf(cellStr));
        } else if (claz.equals(double.class.getName())) {
            params.add((double) Double.parseDouble(cellStr));
        } else if (claz.equals(long.class.getName())) {
            params.add((long) Long.parseLong(cellStr));
        } else if (claz.equals(Long.class.getName())) {
            params.add(Long.valueOf(cellStr));
        } else if (claz.equals(char.class.getName())) {
            params.add(cellStr.toCharArray()[0]);
        } else if (claz.equals(char[].class.getName())) {
            params.add(cellStr.toCharArray());
        } else if (claz.equals(Short.class.getName())) {
            params.add(Short.valueOf(cellStr));
        } else if (claz.equals(short.class.getName())) {
            params.add((short) Short.parseShort(cellStr));
        }
    }

    private static BasicTypeReference checkFieldType(String claz) throws Exception {
        if (claz.equals(String.class.getName())) {
            return StandardBasicTypes.STRING;
        } else if (claz.equals(Integer.class.getName())) {
            return StandardBasicTypes.INTEGER;
        } else if (claz.equals(int.class.getName())) {
            return StandardBasicTypes.INTEGER;
        } else if (claz.equals(Float.class.getName())) {
            return StandardBasicTypes.FLOAT;
        } else if (claz.equals(float.class.getName())) {
            return StandardBasicTypes.FLOAT;
        } else if (claz.equals(Date.class.getName())) {
            return StandardBasicTypes.DATE;
        } else if (claz.equals(Double.class.getName())) {
            return StandardBasicTypes.DOUBLE;
        } else if (claz.equals(double.class.getName())) {
            return StandardBasicTypes.DOUBLE;
        } else if (claz.equals(long.class.getName())) {
            return StandardBasicTypes.LONG;
        } else if (claz.equals(Long.class.getName())) {
            return StandardBasicTypes.LONG;
        } else if (claz.equals(char.class.getName())) {
            return StandardBasicTypes.STRING;
        } else if (claz.equals(Short.class.getName())) {
            return StandardBasicTypes.SHORT;
        } else if (claz.equals(short.class.getName())) {
            return StandardBasicTypes.SHORT;
        }

        throw new Exception("没有匹配到对应heibernate类型");
    }

    /**
     * 党当数据库的字段名称与实体类名称一样时（不区分大小写）可以使用
     */
    public static String getClassAlise(Class<?> claz) {
        List<Field> list = new ArrayList<>();
        list.addAll(Arrays.asList(claz.getDeclaredFields()));
        String sql = "";
        for (Field filed : list) {
            Alise alise = filed.getAnnotation(Alise.class);
            if (alise == null) {
                continue;
            }
            sql += "t." + filed.getName() + " as " + filed.getName() + ",";
        }

        if (sql.contains(",")) {
            sql = sql.substring(0, sql.lastIndexOf(","));
        } else {
            sql = " * ";
        }

        return sql;
    }

    public static void setValue(Object val, Object object, Field field) throws Exception {
        if (val == null) {
            return;
        }
        String value = String.valueOf(val);
        Class<?> columaTypeName = field.getType();
        field.setAccessible(true);
        if (columaTypeName.equals(Long.class)) {
            field.set(object, Long.parseLong(value));
        } else if (columaTypeName.equals(Double.class)) {
            field.set(object, Double.parseDouble(value));
        } else if (columaTypeName.equals(Float.class)) {
            field.set(object, Float.parseFloat(value));
        } else if (columaTypeName.equals(int.class)) {
            field.set(object, Integer.parseInt(value));
        } else if (columaTypeName.equals(Integer.class)) {
            field.set(object, Integer.parseInt(value));
        } else if (columaTypeName.equals(BigDecimal.class)) {
            field.set(object, new BigDecimal(value));
        } else if (columaTypeName.equals(String.class)) {
            field.set(object, value);
        } else if (columaTypeName.equals(Double.class)) {
            field.set(object, Double.valueOf(value));
        } else if (columaTypeName.equals(Short.class)) {
            field.set(object, Short.valueOf(value));
        }
    }

    public static boolean isSimpleType(Class<?> claz) {
        if (claz.equals(String.class)) {
            return true;
        } else if (claz.equals(Integer.class)) {
            return true;
        } else if (claz.equals(int.class)) {
            return true;
        } else if (claz.equals(Float.class)) {
            return true;
        } else if (claz.equals(float.class)) {
            return true;
        } else if (claz.equals(Double.class)) {
            return true;
        } else if (claz.equals(double.class)) {
            return true;
        } else if (claz.equals(long.class)) {
            return true;
        } else if (claz.equals(Long.class)) {
            return true;
        } else if (claz.equals(char.class)) {
            return true;
        } else if (claz.equals(char[].class)) {
            return true;
        } else if (claz.equals(Short.class)) {
            return true;
        } else if (claz.equals(short.class)) {
            return true;
        } else if(claz.equals(BigDecimal.class)){
            return true;
        }
        return false;
    }


    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
    }
}
